package com.starsoft.smdc.crawler.common;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.starsoft.frame.util.DateUtil;
import com.starsoft.smdc.bean.SmdcFundNavPre;
import com.starsoft.smdc.bean.SmdcHandicap;
import com.starsoft.smdc.bean.SmdcMarketDaily;
import com.starsoft.smdc.bean.SmdcMarketDailyId;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.crawler.eastmoney.FundNavPreEastmoney;
import com.starsoft.smdc.crawler.sina.HandicapSina;
import com.starsoft.smdc.crawler.xueqiu.HandicapXueqiu;
import com.starsoft.smdc.util.SecurityType;

import cn.hutool.core.collection.CollUtil;

@Component
public class HandicapCrawlerImpl extends CrawlerService implements HandicapCrawler{

	private static Logger logger = LoggerFactory.getLogger(HandicapCrawlerImpl.class);
	
	private Map<String, SmdcHandicap> handicapCache = new HashMap<>();
	// 缓存有效时间2mins
	private int validateTime = 1000*60*2;

	@Autowired
	protected HandicapSina handicapSina;
	
	@Autowired
	protected HandicapXueqiu handicapXueqiu;
	
	@Autowired
	protected FundNavPreEastmoney fundNavPre;
	
	public SmdcHandicap getHandicap(SmdcSecurity security){
		return this.getHandicap(security, true);
	}
	
	public SmdcHandicap getHandicap(SmdcSecurity security, boolean enableCache) {
		List<SmdcHandicap> handicapList=  this.getHandicap(Arrays.asList(security), enableCache);
		if(handicapList.size()>0) return handicapList.get(0);
		return null;
	}

	@Override
	public List<SmdcHandicap> getHandicap(List<SmdcSecurity> securityList) {
		return getHandicap(securityList, true);
	}
	
	public synchronized List<SmdcHandicap> getHandicap(List<SmdcSecurity> securityList, boolean enableCache){
		long now = new Date().getTime();
		if(securityList==null || securityList.isEmpty()){
			return new ArrayList<>();
		}
		
		List<SmdcSecurity> securityListOf = securityList.stream().filter(a -> "of".equalsIgnoreCase(a.getExchange()))
				.collect(Collectors.toList());
		
		securityList = securityList.stream().filter(a -> !"of".equalsIgnoreCase(a.getExchange()))
				.collect(Collectors.toList());
		
		Map<String, SmdcHandicap> handicapResult = new HashMap<>();
		for (SmdcSecurity security : securityList) {
			SmdcHandicap handicap = handicapCache.get(security.getSecId());
			boolean isCacheValidate = false;
			if (handicap != null && DateUtil.isToday(handicap.getUpdateTime())) {
				if (!holidayService.isBeforeClose(handicap.getUpdateTime())) {
					isCacheValidate = true;
				} else if (now - handicap.getUpdateTime().getTime() < validateTime && enableCache) {
					isCacheValidate = true;
				}
			}
			if (isCacheValidate) {
				handicapResult.put(security.getSecId(), handicap);
			}
		}
		List<SmdcSecurity> left = securityList.stream().filter(a->!handicapResult.containsKey(a.getSecId())).collect( Collectors.toList());
		handicapSina.getHandicap(left).forEach(a->handicapResult.put(a.getSecId(), a));
		
		left=securityList.stream().filter(a->!handicapResult.containsKey(a.getSecId())).collect( Collectors.toList());
		handicapXueqiu.getHandicap(left).forEach(a->handicapResult.put(a.getSecId(), a));
		
		handicapCache.putAll(handicapResult);
		
		getHandicapForOfFund(securityListOf, handicapResult);
		
		return new ArrayList<>(handicapResult.values());
	}
	
	public List<SmdcMarketDaily> update(SmdcSecurity security, Date beginDate) {
		return update(Arrays.asList(security), Arrays.asList(beginDate));
	}
	
	@Override
	public List<SmdcMarketDaily> update(List<SmdcSecurity> securityList, List<Date> beginDates) {
		List<SmdcMarketDaily> result = updateSuspension(securityList, beginDates);
		result.addAll(updateHandicap(securityList, beginDates));
		return result;
	}

	private void getHandicapForOfFund(List<SmdcSecurity> securityList, Map<String, SmdcHandicap> handicapResult) {
		if(CollUtil.isEmpty(securityList)) return;
		Map<String, SmdcFundNavPre> navPre = fundNavPre.get(securityList);
		
		for (SmdcFundNavPre value : navPre.values()) {
			SmdcHandicap handicap = new SmdcHandicap();
			handicap.setSecId(value.getSecId());
			handicap.setPrice(value.getPreNav());
			handicapResult.put(value.getSecId(), handicap);
		}
	}
	
	/**
	 * 更新停牌股价
	 * @param securityList
	 * @param beginDates
	 * @return
	 */
	private List<SmdcMarketDaily> updateSuspension(List<SmdcSecurity> securityList, List<Date> beginDates) {
		List<SmdcMarketDaily> result = new ArrayList<SmdcMarketDaily>();
		Date now = new Date();
		Date nowDate = holidayService.getBusinessDay(now, true);
		if(holidayService.isBusinessDay(now) && holidayService.isBeforeClose(now)){
			nowDate = holidayService.getNextBusinessDay(now, -1);
		}
		
		for (int i = 0; i < securityList.size(); i++) {
			SmdcSecurity security = securityList.get(i);
			if("of".equalsIgnoreCase(security.getExchange())) continue;
			Date secBeginDate = DateUtil.floorTime(beginDates.get(i));
			if (secBeginDate.after(nowDate) || SecurityType.isIndex(security.getSecType())) {
				continue;
			}
			SmdcHandicap handicap = handicapSina.getHandicap(security);
			if(handicap==null || handicap.isOpen()){
				continue;
			}
			while(!secBeginDate.after(nowDate)){
				SmdcMarketDaily market = handicap.toMarket();
				market.getId().setTradeDate(secBeginDate);
				result.add(market);
				secBeginDate = holidayService.getNextBusinessDay(secBeginDate, 1);
			}
		}
		marketDailyDao.saveOrUpdateBatch(result);
		return result;
	}
	
	private List<SmdcMarketDaily> updateHandicap(List<SmdcSecurity> securityList, List<Date> beginDates) {
		Date now = new Date();
		if (holidayService.isBeforeClose(now)) {
			now = holidayService.getNextBusinessDay(now, -1);
		}
		List<SmdcMarketDaily> result = new ArrayList<SmdcMarketDaily>();
		for (int i = 0; i < securityList.size(); i++) {
			SmdcSecurity security = securityList.get(i);
			if (!SecurityType.isBond(security.getSecType()) && !SecurityType.isFund(security.getSecType())
					&& !SecurityType.isStock(security.getSecType())) {
				continue;
			}
			if("of".equalsIgnoreCase(security.getExchange())) continue;
			Date secBeginDate = DateUtil.floorTime(beginDates.get(i));
			if (secBeginDate.after(now)) {
				continue;
			}
			
			String secId = security.getSecId();
			SmdcMarketDaily market = marketDailyDao.get(new SmdcMarketDailyId(secId, now));
			if (market == null) {
				continue;
			}
			if (market.getBuy1() != null && market.getSell1() != null) {
				continue;
			}
			SmdcHandicap handicap = handicapSina.getHandicap(security);
			if(handicap==null) continue;
			market.setBuy1(handicap.getBuy1());
			market.setBuyVol1(handicap.getBuyVol1());
			market.setSell1(handicap.getSell1());
			market.setSellVol1(handicap.getSellVol1());
			marketDailyDao.saveOrUpdate(market);
			result.add(market);
		}
		return result;
	}

	@Override
	protected String getTargetSystem() {
		return null;
	}

	@Override
	protected String convertSecId(String secId, boolean isToLocal) {
		return null;
	}

}
